package ddz.db.service;

import com.kaka.notice.Message;
import com.kaka.notice.Proxy;
import com.kaka.notice.annotation.Model;
import ddz.constants.OpCode;
import ddz.core.GameMode;
import ddz.db.dao.UserDao;
import ddz.db.entity.UserInfo;
import ddz.numerical.manager.ConfPlaceInfoManager;
import ddz.numerical.pojo.ConfPlaceInfo;

import java.util.*;
import java.util.function.Consumer;

/**
 * 玩家匹配
 *
 * @author zkpursuit
 */
@Model
public class MatcherService extends Proxy implements MatchTimeoutProcessor, MatchResultProcessor {

    protected final Map<String, MatchPool> map;

    private MatcherService() {
        map = new HashMap<>();
    }

    /**
     * 是否正在匹配中
     *
     * @param mode
     * @param place
     * @param uid
     * @return
     */
    public synchronized boolean isWaitingMatch(int mode, int place, long uid) {
        String matcherId = mode + ":" + place;
        if (!map.containsKey(matcherId)) {
            return false;
        }
        MatchPool matcher = map.get(matcherId);
        return matcher.isMatching(uid);
    }

    /**
     * 退出匹配
     *
     * @param uid
     * @param existAfterConsumer 退出后的处理函数
     * @return
     */
    public synchronized void exitMatch(final long uid, Consumer<MatchPool> existAfterConsumer) {
        if (uid <= 0) return;
        Collection<MatchPool> collection = map.values();
        for (MatchPool matcher : collection) {
            MatchMember matchMember = matcher.removePlayerFromMatchPool(uid);
            if (matchMember != null && existAfterConsumer != null) {
                existAfterConsumer.accept(matcher);
            }
        }
    }

    public void addWaitMatchPlayer(int mode, int place, long uid, int score) {
        addWaitMatchPlayer(mode, place, uid, score, null);
    }

    /**
     * 添加匹配成员
     *
     * @param mode
     * @param place
     * @param uid
     * @param score
     * @param params
     */
    public synchronized void addWaitMatchPlayer(int mode, int place, long uid, int score, Map<String, Object> params) {
        if (mode <= 0) {
            mode = GameMode.NORMAL.getId();
        } else {
            if (!GameMode.isExists(mode)) {
                mode = GameMode.NORMAL.getId();
            }
        }
        ConfPlaceInfoManager placeInfoManager = this.retrieveProxy(ConfPlaceInfoManager.class);
        if (place < 0) {
            UserDao userDao = this.retrieveProxy(UserDao.class);
            UserInfo userInfo = userDao.getUserInfo(uid);
            if (userInfo != null) {
                ConfPlaceInfo confPlaceInfo = placeInfoManager.getConfPlaceInfoByBounds(mode, userInfo.getGold());
                if (confPlaceInfo != null) place = confPlaceInfo.getPlace();
                else place = 1;
            } else {
                place = 1;
            }
        } else {
            ConfPlaceInfo confPlaceInfo = placeInfoManager.getConfPlaceInfo(mode, place);
            if (confPlaceInfo == null) {
                place = 1;
            } else {
                place = confPlaceInfo.getPlace();
            }
        }
        String matcherId = mode + ":" + place;
        MatchPool matcher;
        if (!map.containsKey(matcherId)) {
            matcher = map.computeIfAbsent(matcherId, k -> new MatchPool(matcherId, 3));
            matcher.setMatchResultProcessor(this);
            boolean matchRobot = false;
            //普通癞子模式和连胜赛中的癞子模式都不匹配机器人
            if (mode != GameMode.LAIZI.getId()) {
                if (mode == GameMode.LIAN_WIN.getId()) {
                    if (place != GameMode.LAIZI.getId()) { //连胜赛模式中癞子玩法没有机器人
                        matchRobot = true;
                    }
                } else {
                    if (place != 3 && place != 4) { //高级场和大师场不参与匹配机器人
                        matchRobot = true;
                    }
                }
            }
            if (matchRobot) {
                matcher.setMatchTimeoutProcessor(this);
            }
        } else {
            matcher = map.get(matcherId);
        }
        matcher.putPlayerIntoMatchPool(uid, score, params);
    }

    /**
     * 定时处理匹配
     */
    public synchronized void matchTick() {
        map.forEach((String id, MatchPool matcher) -> {
            matcher.matchProcess();
        });
    }

    /**
     * 匹配超时时间设定
     *
     * @return 超时时间
     */
    @Override
    public final long timeout(MatchPool matchPool) {
        return 5000;
    }

    /**
     * 处理匹配超时
     *
     * @param members 超时的匹配玩家
     */
    @Override
    public final void doMatchTimeout(MatchPool matchPool, List<MatchMember> members) {
        if (members != null && !members.isEmpty()) {
            List<MatchMember> list = new ArrayList<>(2);
            while (members.size() > 0) {
                MatchMember member = members.remove(members.size() - 1);
                list.add(member);
                if (members.size() > 0) {
                    member = members.remove(members.size() - 1);
                    list.add(member);
                }
                MatchMember[] array = new MatchMember[3];
                list.toArray(array);
                for (int i = list.size(); i < 3; i++) {
                    array[i] = new MatchMember(0, 0, null); //不足填充机器人
                }
                list.clear();
                MatchResult matchResult = new MatchResult(matchPool.getId(), array);
                //System.out.println(JsonUtils.toJsonString(matchResult));
                this.sendMessage(new Message(OpCode.cmd_create_desk, matchResult), true);
            }
        }
    }

    /**
     * 处理匹配结果
     *
     * @param result 匹配到的一组结果
     */
    @Override
    public void doMatchResult(MatchPool matchPool, MatchResult result) {
        //System.out.println("匹配到的一组玩家：");
        this.sendMessage(new Message(OpCode.cmd_create_desk, result), true);
    }
}
